Bir Windows API programında, Superclassing yöntemi kullanılarak, sistemde kayıtlı BUTTON temel işlevleriyle yeni bir pencere sınıfı oluşturulur ve bu sınıfa ek özellikler kazandırılır.
Yeni oluşturulan sınıf RegisterClassEx() fonksiyonu ile sisteme kaydedildikten sonra, yeni sınıf adıyla, aynı özelliklere sahip olan ve aynı pencere fonksiyonunu kullanan birden fazla buton oluşturabiliriz.
Programda yer alacak main.c, resource.rc ve manifest.xml dosyalarının içeriği aşağıdaki şekilde olacaktır:
main.c
#if defined(UNICODE) && !defined(_UNICODE)
#define _UNICODE
#elif defined(_UNICODE) && !defined(UNICODE)
#define UNICODE
#endif
#define _WIN32_WINNT 0x0501
#define _WIN32_IE 0x0501
#include <tchar.h>
#include <windows.h>
#include <commctrl.h>
#define IDC_BUTTON01 1001
#define IDC_BUTTON02 1002
/* Declare Windows procedure */
LRESULT CALLBACK WindowProcedure(HWND, UINT, WPARAM, LPARAM);
/* Yeni oluşturulan button sınıf cinsinden super sınıfı sisteme kaydeden fonksiyon bildirimi */
void RegisterSuperButton(void);
/* Yeni oluşturulan button sınıf cinsinden super sınıfın pencere fonksiyon bildirimi */
LRESULT CALLBACK SuperButtonProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
/* Make the class name into a global variable */
TCHAR szClassName[ ] = _T("CodeBlocksWindowsApp");
HWND hwndButton01, hwndButton02;
/* Orjinal sınıf fonksiyonunun kaydedileceği değişken tanımı */
WNDPROC BtnOrigProc;
int WINAPI WinMain(HINSTANCE hThisInstance,
HINSTANCE hPrevInstance,
LPSTR lpszArgument,
int nCmdShow)
{
HWND hwnd; /* This is the handle for our window */
MSG messages; /* Here messages to the application are saved */
WNDCLASSEX wincl; /* Data structure for the windowclass */
/* The Window structure */
wincl.hInstance = hThisInstance;
wincl.lpszClassName = szClassName;
wincl.lpfnWndProc = WindowProcedure; /* This function is called by windows */
wincl.style = CS_DBLCLKS; /* Catch double-clicks */
wincl.cbSize = sizeof (WNDCLASSEX);
/* Use default icon and mouse-pointer */
wincl.hIcon = LoadIcon (NULL, IDI_APPLICATION);
wincl.hIconSm = LoadIcon (NULL, IDI_APPLICATION);
wincl.hCursor = LoadCursor (NULL, IDC_ARROW);
wincl.lpszMenuName = NULL; /* No menu */
wincl.cbClsExtra = 0; /* No extra bytes after the window class */
wincl.cbWndExtra = 0; /* structure or the window instance */
/* Use Windows's default colour as the background of the window */
wincl.hbrBackground = (HBRUSH) COLOR_BACKGROUND;
/* Register the window class, and if it fails quit the program */
if (!RegisterClassEx (&wincl)) return 0;
/* The class is registered, let's create the program*/
hwnd = CreateWindowEx (
0, /* Extended possibilites for variation */
szClassName, /* Classname */
_T("Superclassing Button"), /* Title Text */
WS_OVERLAPPEDWINDOW, /* default window */
CW_USEDEFAULT, /* Windows decides the position */
CW_USEDEFAULT, /* where the window ends up on the screen */
400, /* The programs width */
300, /* and height in pixels */
HWND_DESKTOP, /* The window is a child-window to desktop */
NULL, /* No menu */
hThisInstance, /* Program Instance handler */
NULL /* No Window Creation data */
);
/* Make the window visible on the screen */
ShowWindow (hwnd, nCmdShow);
/* Run the message lmoop. It will run until GetMessage() returns 0 */
while (GetMessage (&messages, NULL, 0, 0))
{
/* Translate virtual-key messages into character messages */
TranslateMessage(&messages);
/* Send message to WindowProcedure */
DispatchMessage(&messages);
}
/* The program return-value is 0 - The value that PostQuitMessage() gave */
return messages.wParam;
}
/* This function is called by the Windows function DispatchMessage() */
LRESULT CALLBACK WindowProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message) /* handle the messages */
{
case WM_CREATE:
{
RegisterSuperButton();
hwndButton01 = CreateWindowEx(0, "MYBUTTON", "Button01",
WS_CHILD | WS_VISIBLE, 20, 20, 120, 25,
hwnd, (HMENU) IDC_BUTTON01, NULL, NULL);
hwndButton02 = CreateWindowEx(0, "MYBUTTON", "Button02",
WS_CHILD | WS_VISIBLE, 20, 60, 120, 25,
hwnd, (HMENU) IDC_BUTTON02, NULL, NULL);
}
break;
case WM_COMMAND:
{
if (HIWORD(wParam) == BN_CLICKED) {
switch(LOWORD(wParam)) {
case IDC_BUTTON01:
MessageBox(NULL, "Button01 tıklandı.", "Buton tıklama", MB_OK);
break;
case IDC_BUTTON02:
MessageBox(NULL, "Button02 tıklandı.", "Buton tıklama", MB_OK);
break;
}
}
}
break;
case WM_DESTROY:
PostQuitMessage (0); /* send a WM_QUIT to the message queue */
break;
default: /* for messages that we don't deal with */
return DefWindowProc (hwnd, message, wParam, lParam);
}
return 0;
}
/* Yeni oluşturulan button sınıf cinsinden super sınıfı sisteme kaydeden fonksiyon */
void RegisterSuperButton(void)
{
WNDCLASSEX wndSupButton = {0};
// GetClassInfoEx() fonksiyonu çağrılmadan mutlaka değer atanmalıdır.
wndSupButton.cbSize = sizeof (WNDCLASSEX);
// Sistem BUTTON sınıf bilgisini alma
GetClassInfoEx(0, "BUTTON", &wndSupButton);
// Program Instance değerini sınıf Instance değişkenine atama
wndSupButton.hInstance = (HINSTANCE) GetModuleHandle(NULL);
// Sistem button sınıfı temel alınarak oluşturulan yeni superclassing adını değişkenine atama
wndSupButton.lpszClassName = TEXT("MYBUTTON");
// Sistem button sınıfına ait pencere fonksiyonunu bir WNDPROC değişkenine atama
BtnOrigProc = wndSupButton.lpfnWndProc;
// Yeni oluşturulan sınıf için kullanılacak fonksiyonunu orjinal fonksiyon yerine atama
wndSupButton.lpfnWndProc = SuperButtonProc;
// Bu sınıf yapısı için ayrılacak ekstra byte sayısıdır.
wndSupButton.cbClsExtra = 0;
// Bu pencere Instance değeri için ayrılacak ekstra byte sayısıdır. Sıfırdan farklı bir değer olmalıdır.
wndSupButton.cbWndExtra = 100;
// Yeni oluşturulan sınıfı sisteme kaydetme
RegisterClassEx (&wndSupButton);
}
/* Yeni oluşturulan button sınıf cinsinden super sınıfın pencere fonksiyonu */
LRESULT CALLBACK SuperButtonProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static int inButton;
static HWND hwndButton;
switch (message) {
case WM_PAINT:
{
PAINTSTRUCT ps;
char cdizi[40];
BeginPaint(hwnd, &ps);
SetTextColor(ps.hdc, RGB(236, 236, 236));
SetBkMode(ps.hdc, TRANSPARENT);
if (inButton && (hwndButton == hwnd)) FillRect(ps.hdc, &ps.rcPaint, (HBRUSH)CreateSolidBrush(RGB(100, 205, 22)));
else FillRect(ps.hdc, &ps.rcPaint, (HBRUSH)CreateSolidBrush(RGB(90, 180, 20)));
GetWindowText(hwnd, cdizi, sizeof(cdizi));
DrawText(ps.hdc, cdizi, -1, &ps.rcPaint, DT_SINGLELINE | DT_CENTER | DT_VCENTER);
EndPaint(hwnd, &ps);
// return 0; // Button sınıf penceresinin işlem yapmaması için
}
break;
case WM_MOUSEMOVE:
{
hwndButton = hwnd;
if (GetCapture() != hwnd) {
// Mouse button penceresine henüz girdi.
inButton=1;
SetCapture(hwnd);
}
else {
RECT rect;
POINT pt = { LOWORD(lParam), HIWORD(lParam) };
GetWindowRect(hwnd, &rect);
ClientToScreen(hwnd, &pt);
if (!PtInRect(&rect, pt)) {
// Mouse button penceresinden ayrıldı.
inButton=0;
ReleaseCapture();
}
}
}
break;
}
return CallWindowProc(BtnOrigProc, hwnd, message, wParam, lParam);
}
resource.rc
1 24 "manifest.xml"
manifest.xml
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity version="1.0.0.0" processorArchitecture="*" name="CompanyName.ProductName.YourApplication" type="win32" />
<description>Your application description here.</description>
<dependency>
<dependentAssembly>
<assemblyIdentity type="win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" processorArchitecture="*" publicKeyToken="6595b64144ccf1df" language="*" />
</dependentAssembly>
</dependency>
</assembly>
Program derleyip çalıştırdığımızda aşağıdakine benzer bir ekran görüntüsü karşımıza gelecektir: